//-------------------------------------- 
// easy-riscv iex lsu
//--------------------------------------

module EASY_RISCV_IEX_LSU #(
    parameter   DAT_W   = 32   
    ,          ADDR_W   = 10            // 1024 x 32-bit = 4KB  
    ,           SFT_W   = 5             // RV32I: 5, RV64I: 6   
    ,   DMEM_ADDR_OFS   = 32'h800       // offset 2KB instruction space 
    ,           ENA_W   = DAT_W/8           
    ,       GPR_IDX_W   = 5             // GPR_IDX   
)
//--------------------------------------
(
//--------------------------------------
    input                       i_clk
,   input                       i_rst_n
,   input                       i_instr_vld_d0 
,   input       [5      :0]     i_what_is_instr_d0  
,   input       [DAT_W-1:0]     i_cur_pc_d0                     // PC buffer    
,   input       [4      :0]     i_shamt_d0      
,   input       [DAT_W-1:0]     i_imm_dat_d0   
,   input       [DAT_W-1:0]     i_rf_r1_dat_d0     
,   input       [DAT_W-1:0]     i_rf_r2_dat_d0
,   input   [GPR_IDX_W-1:0]     i_rf_rd_idx_d0                  // target register index                    
//--------------------------------------
,   output reg                  o_branch_vld_e0                 // branch vld
,   output reg  [DAT_W-1:0]     o_branch_pc_e0  
,   output reg                  o_unaligned_access_fault_e0
,   output reg  [5      :0]     o_what_is_instr_e1  
,   output reg  [ENA_W-1:0]     o_rf_rd_be_e1                   // 1: byte read data vld
,   output reg  [GPR_IDX_W-1:0] o_rf_rd_idx_e1                  // target register index                    
,   output      [DAT_W-1:0]     o_rf_rd_dat_e1 
,   output  [GPR_IDX_W-1:0]     o_rf_rd_idx_e0                  // target register index                    
,   output reg                  o_rf_rd_vld_e0                  // target register write valid
,   output reg  [DAT_W-1:0]     o_rf_rd_dat_e0                  // target register value
//--------------------------------------
);
//--------------------------------------
localparam DMEM_ADDR_LSB    = $clog2(DAT_W/8)   ;
localparam DMEM_ADDR_MSB    = ADDR_W + DMEM_ADDR_LSB - 1;

//--------------------------------------
wire signed [DAT_W-1:0]     s_rf_r1_dat_e0  ;
wire signed [DAT_W-1:0]     s_rf_r2_dat_e0  ;
wire signed [DAT_W-1:0]     s_imm_dat_e0    ;

// Need Fill !!! 
assign s_imm_dat_e0     = $signed(i_imm_dat_d0)     ;

reg     [DAT_W-1:0]     load_store_addr_e0      ; 
reg     [DAT_W-1:0]     store_data_e0           ; 
wire    [DAT_W-1:0]     nxt_d_sram_addr_e0      ; 

//--------------------------------------
reg                     d_sram_cs       ;   // active high
reg     [ENA_W-1:0]     d_sram_we       ;   // 1: byte enable write, all 0: read
reg     [ENA_W-1:0]     d_rdat_vld      ;   // 1: byte read data vld
wire   [ADDR_W-1:0]     d_sram_addr     ;
reg     [DAT_W-1:0]     d_sram_din      ;
wire    [DAT_W-1:0]     d_sram_dout     ;    

//--------------------------------------
always @(*) begin
    o_rf_rd_vld_e0      = 1'b0          ;     
    o_rf_rd_dat_e0      = {DAT_W{1'b0}} ; 
    o_branch_vld_e0     = 1'b0          ; 
    o_branch_pc_e0      = {DAT_W{1'b0}} ; 
    
    d_sram_cs           = 1'b0          ;
    load_store_addr_e0  = {DAT_W{1'b0}} ;
    store_data_e0       = {DAT_W{1'b0}} ;
    
    case (i_what_is_instr_d0)   
        `RISCV_LUI  : begin
            o_rf_rd_vld_e0  = i_instr_vld_d0    ;
            o_rf_rd_dat_e0  = s_imm_dat_e0      ;
        end
        `RISCV_ADDI : begin
            o_rf_rd_vld_e0  = i_instr_vld_d0    ;   
            o_rf_rd_dat_e0  = s_imm_dat_e0 + i_rf_r1_dat_d0; 
        end
        // BRU FUNC
        // Need Fill !!! 
        
        // LS FUNC
        // Need Fill !!! 
        
        default     : begin
            o_rf_rd_vld_e0      = 1'bx          ;     
            o_rf_rd_dat_e0      = {DAT_W{1'bx}} ; 
            o_branch_vld_e0     = 1'bx          ; 
            o_branch_pc_e0      = {DAT_W{1'bx}} ; 
            
            d_sram_cs           = 1'bx          ;
            load_store_addr_e0  = {DAT_W{1'bx}} ;
            store_data_e0       = {DAT_W{1'bx}} ;
        end
    endcase
end

//--------------------------------------
// no unified address space, 2KB is Instr Space, above 4KB is Data Space
//--------------------------------------
assign nxt_d_sram_addr_e0   = load_store_addr_e0 - DMEM_ADDR_OFS                ;
assign d_sram_addr          = nxt_d_sram_addr_e0[DMEM_ADDR_MSB:DMEM_ADDR_LSB]   ;
        
always @(*) begin
    d_sram_we   = {ENA_W{1'b0}} ;
    d_rdat_vld  = {ENA_W{1'b0}} ;
    o_unaligned_access_fault_e0 = 1'b0  ;
    d_sram_din  = {DAT_W{1'b0}} ;
    // Need Fill !!! 
end

//--------------------------------------
EASY_RISCV_SPRAM_BE #(
    .ADDR_W     (ADDR_W )
,   .DAT_W      (DAT_W  )
)
EASY_RISCV_DMEM_BE_U0 (
    .clk        (i_clk      )   
,   .ce         (d_sram_cs  )        
,   .we         (d_sram_we  )        
,   .addr       (d_sram_addr)      
,   .din        (d_sram_din )  
,   .dout       (d_sram_dout)    
);

//--------------------------------------
// to Write Back
//--------------------------------------
assign o_rf_rd_idx_e0   = i_rf_rd_idx_d0;
assign o_rf_rd_dat_e1   = d_sram_dout   ;

always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        o_rf_rd_be_e1       <= {ENA_W{1'b0}};
        o_what_is_instr_e1  <= 6'd0         ;
    end
    // Need Fill !!! 
end

//--------------------------------------
endmodule
